package fbcache

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/go-redis/redis"
	"github.com/olivere/elastic/v7"
	global2 "longmen/server/config/global"
	"longmen/server/internal/rpc/tencentim/imsdk"
	messages2 "longmen/server/internal/rpc/tencentim/messages"
	"longmen/server/internal/rpc/tencentim/messages/sports"
	"longmen/server/internal/services/nami/services/sports/basketball/bbcache"
	"longmen/server/pkg/common/helper/const"
	"sync"
)

//[
//	[
//		2313858,//纳米比赛id
//		1,//比赛状态，详见状态码->比赛状态
//		[
//			0,//主队比分(常规时间)
//			0,//主队半场比分
//			0,//主队红牌
//			0,//主队黄牌
//			-1,//主队角球，-1表示没有角球数据
//			0,//主队加时比分(120分钟，即包括常规时间比分)，加时赛才有
//			0,//主队点球大战比分(不包含常规时间及加时赛比分)，点球大战才有
//		],
//		[
//			0,//客队比分(常规时间)
//			0,//客队半场比分
//			0,//客队红牌
//			0,//客队黄牌
//			-1,//客队角球，-1表示没有角球数据
//			0,//客队加时比分(120分钟，即包括常规时间比分)，加时赛才有
//			0//客队点球大战比分(不包含常规时间及加时赛比分)，点球大战才有
//		],
//		1516197600,//开球时间戳，上/下半场开球时间(根据比赛状态判断)
//		""//备注信息，可忽略
//	]
//]

type ScoreItem struct {
	Score        int `json:"score"`         // 比分(常规时间)
	HalfScore    int `json:"half_score"`    // 半场比分
	RedCard      int `json:"red_card"`      // 红牌
	YellowCard   int `json:"yellow_card"`   // 黄牌
	CornerKick   int `json:"corner_kick"`   // 角球，-1表示没有角球数据
	OTScore      int `json:"ot_score"`      // 加时比分(120分钟，即包括常规时间比分)，加时赛才有
	PenaltyScore int `json:"penalty_score"` // 点球大战比分(不包含常规时间及加时赛比分)，点球大战才有
}

type Score struct {
	MatchId     int       `json:"match_id"`      // 比赛id
	MatchStatus int       `json:"match_status"`  // 比赛状态，详见状态码->比赛状态
	HomeScore   ScoreItem `json:"home_score"`    // 主队比分
	AwayScore   ScoreItem `json:"away_score"`    // 客队比分
	KickOutTime int64     `json:"kick_out_time"` //开球时间戳，上/下半场开球时间(根据比赛状态判断)
	TimePlayed  uint32    `json:"time_played"`   // 进行时间 计算方式参考
}
type PublishScoreInterface interface {
	GetScore() Score
}

type ScoreCache struct {
	rds redis.UniversalClient
	es  *elastic.Client
}

var scoreCache *ScoreCache
var scoreCacheOnce sync.Once

func NewScoreRedis() *ScoreCache {
	scoreCacheOnce.Do(func() {
		scoreCache = &ScoreCache{
			rds: global2.GetRds(),
			es:  global2.GetEs(),
		}
	})
	return scoreCache
}

// 生成足球即时比分key
func (s *ScoreCache) genOddsKey(matchId int) string {
	return fmt.Sprintf("match_live:football_score:%d", matchId)
}

func (s *ScoreCache) PublishLiveScore(pubs []PublishScoreInterface) error {
	data := make([]Score, 0)
	pp := s.rds.Pipeline()
	for _, pub := range pubs {
		score := pub.GetScore()
		data = append(data, score)
		id := score.MatchId
		newMsg := sports.FootballScoreMessage{
			SentMessageStruct: messages2.SentMessageStruct{Type: messages2.ScoreLiveMessageType},
			Scores:            score,
		}
		marshal, _ := json.Marshal(newMsg)

		pp.Set(s.genOddsKey(id), string(marshal), bbcache.CacheExpire)
		imsdk.GetSdk().BroadcastInterface(id, newMsg, 0)
	}
	_, err := pp.Exec()
	if err != nil {
		global2.Log.Errorf("Pipeline run error: %v", err)
	}
	s.writeToes(data)
	return nil
}

func (s *ScoreCache) LiveScore(data []Score) error {
	pp := s.rds.Pipeline()
	for _, pub := range data {
		id := pub.MatchId
		newMsg := sports.FootballScoreMessage{
			SentMessageStruct: messages2.SentMessageStruct{Type: messages2.ScoreLiveMessageType},
			Scores:            pub,
		}
		marshal, _ := json.Marshal(newMsg)

		pp.Set(s.genOddsKey(id), string(marshal), bbcache.CacheExpire)
	}
	_, err := pp.Exec()
	if err != nil {
		global2.Log.Errorf("Pipeline run error: %v", err)
	}
	s.writeToes(data)
	return nil
}

// GetScoreCache 获取缓存
func (s *ScoreCache) GetScoreCache(matchId int) string {
	result, err := s.rds.Get(s.genOddsKey(matchId)).Result()
	if err != nil {
		return ""
	}
	return result
}

// 篮球比分KEY
func (s *ScoreCache) getEsIndexName() string {
	return _const.ES_MATCH_FOOTBALL_SCORE
}

func (s *ScoreCache) InitEsIndex() {
	s.es.Index().Index(s.getEsIndexName())
}

func (s *ScoreCache) writeToes(sendData []Score) {
	bulks := make([]*elastic.BulkIndexRequest, 0)
	total := 3000 // 3000条批量写一次
	writeCount := 0
	for _, datum := range sendData {
		// 赛程ID
		id := fmt.Sprintf("%d", datum.MatchId)
		bulks = append(bulks, elastic.NewBulkIndexRequest().Index(s.getEsIndexName()).Doc(datum).Id(id))
		writeCount++
		if writeCount == total {
			s.bulkToEs(bulks)
			bulks = make([]*elastic.BulkIndexRequest, 0)
		}
	}

	if len(bulks) > 0 {
		s.bulkToEs(bulks)
	}
}
func (s *ScoreCache) bulkToEs(records []*elastic.BulkIndexRequest) {
	bulk := s.es.Bulk()
	for i := range records {
		bulk.Add(records[i])
	}
	res, err := bulk.Do(context.Background())
	if err != nil {
		global2.Log.Errorf("exec bulk to es : %v", err)
		return
	}
	for _, item := range res.Failed() {
		global2.Log.Errorf("write to es err: %s", item.Error.Reason)
	}

}
